Serial++ Interrupt Driven Serial Ports for C++ from Cortlandt Technologies Serial++ Version 1.01 by Cortlandt Technologies P.O. Box 195 Pleasantville NY 10570 _______ ____|__ | (R) --| | |------------------- | ____|__ | Association of | | |_| Shareware |__| o | Professionals -----| | |--------------------- |___|___| MEMBER This program is produced by a member of the Association of Shareware Professionals (ASP). ASP wants to make sure that the shareware principle works for you. If you are unable to resolve a shareware-related problem with an ASP member by contacting the memberdirectly, ASP may be able to help. The ASP Ombudsman can help you resolve a dispute or problem with an ASP member, but does not provide technical support for members' products. Please write to the ASP Ombudsman at 545 Grover Road, Muskegon, MI 49442 or send a CompuServe message via CompuServe Mail to ASP Ombudsman 70007,3536. Copyright Notice: Serial++ is Copyright (c) 1991 by Cortlandt Technologies. All rights reserved. This manual is Copyright (c) 1991 by Cortlandt Technologies. All rights reserved. Warranty Disclaimer CORTLANDT TECHNOLOGIES MAKES NO WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. CORTLANDT TECHNOLOGIES DOES NOT ASSUME ANY LIABILITY FOR THE USE OF THIS SOFTWARE BEYOND THE ORIGINAL PURCHASE PRICE OF THIS SOFTWARE. IN NO EVENT WILL CORTLANDT TECHNOLOGIES BE LIABLE TO YOU FOR ANY ADDITIONAL DAMAGES, INCLUDING ANY LOST PROFITS, LOST SAVINGS, OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OF, OR INABILITY TO USE, THIS SOFTWARE AND ITS ACCOMPANYING DOCUMENTATION, EVEN IF CORTLANDT TECHNOLOGIES, HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Table of Contents Introduction........................................4 Hardware/Software Requirements......................5 Installing Serial++.................................6 Installing .LIB Library Files.......................7 Installing .H Include Files.........................8 Using This Manual and Serial++......................10 Serial Ports...................................10 Break Trapping.................................13 Memory Models..................................13 Serial++ with Overlays.........................14 SerialPort Function Reference.......................14 constructor....................................14 destructor.....................................15 getBreakOff....................................16 getCommPort....................................17 getDataBits....................................17 getLSR.........................................18 getMSR.........................................19 getParity......................................20 getSpeed.......................................21 getStopBits....................................21 inbyte.........................................22 inmem..........................................23 instr..........................................24 isOwner........................................25 lineOK.........................................26 outbyte........................................27 outmem.........................................27 outstr.........................................28 sendBreak......................................28 setMCR.........................................29 unbyte.........................................30 constructor....................................31 destructor.....................................31 breakCt........................................32 isBreak........................................33 isCaptured.....................................34 isOwner........................................35 operator().....................................35 reset..........................................36 Serial++ is Shareware..........................38 Registration Information.......................38 Limited Distribution License...................39 Introduction Serial++ is a library of small, safe, and efficient routines that bring interrupt driven serial port support to your C++ programs. It is compiled and linked with the Borland C++ compiler, and supplied in the form of a set of ready to link object libraries. The routines in Serial++ are as easy to use as file i/o in C, yet give you complete access to the registers of the 8250 UART, should you require it. They allow you to read characters from and write characters to two serial ports simultaneously, in a fashion very similar to stream i/o in C. Support for iostreams as defined in C++ version 2.0 is not available as of this release. Implemented as C++ classes, the Serial++ library handles multiple ports and multiple instantiations with ease. The SerialPort and BreakTrap classes contain all the internal housekeeping necessary to deal with multiple instances of the each class using a single port. It is because of this feature that Serial++ lends itself nicely to event driven applications. Serial++ protects your applications from keyboard breaks, (pressing the Control-Break or Control-C keys), to insure that the necessary interrupt housekeeping is completed before terminating,. This guarantees that premature closing of a Serial++ application will not leave your system with invalid service routine addresses hooked to the serial interrupts.. By default SerialPort will perform an orderly shutdown when a break key is pressed, and exit to DOS. You can, however, specify that keyboard breaks be handled in your own application code, in which case SerialPort will continue to operate and ignore the break. See the section on break trapping for details on how this works. You can also use the keyboard break handling in Serial++ by itself. The BreakTrap class is entirely independent of the SerialPort class. Serial++ is linked into your C++ programs just like any other library. There is absolutely no requirement for external TSR's - - applications using Serial++ are completely self contained. 4 Hardware/Software Requirements Serial++ may be used on any PC or PC-AT compatible computer, running on an Intel(Tm) 8088, 8086, or 80x86 family processor or compatible, that uses standard port addresses for COM1 and COM2. It is worth mentioning that Serial++ assumes that your serial port hardware makes use of the National Semiconductor 8250 UART chip, or a clone of it. It is almost unheard of to find hardware that uses anything else, so if you don't know what your serial board uses, you're alright. Be aware of this issue though, if you use some sort of exotic or proprietary serial boards in your machine. When in doubt, try executing the demo program on your target machine. While Serial++ is unaffected by machine speed, and has been run on machines operating at 4.77 to 33 MHz, it does expect to find the serial ports and interrupt vector addresses at very specific locations: Device Base i/o Address Int. Vector Address COM1: 0x03F8 0x000C COM2 0x02F8 0x000B Keyboard: Ctrl-Brk n/a 0x0023 Ctrl-C n/a 0x001B If you have difficulty getting the demo program to work, you might want to consult the technical documentation that comes with your computer to verify the addresses shown above. Serial++ requires MS-DOS, version 2.11 or higher. [The library has been tested and works with version 5.00]. Serial++ uses DOS functions for saving, setting, and restoring interrupt service routine addresses. While it is running, Serial++ traps the interrupts mentioned in the table above. Although it restores the addresses of the prior service routines upon exit, while it is running Serial++ could interfere with any TSR's that utilizes any of the listed interrupts. Consult the documentation of any TSR's you use that provide serial communications or respond to the Control-Break or Control-C keys. 5 Installing Serial++ Serial++ is distributed as a self-extracting archive file, SPP.EXE. The first step in installation is to copy this file into a work directory and execute it by typing: C:>spp at the DOS command prompt. SPP will announce each file as it is unpacked looking something like this: . . . READ.ME . PACKING.LST . SPPL.LIB . BREAK.H . SERIAL.H SPPS.LIB . . . . After you have expanded SPP.EXE into its component files, you may delete it from your install work directory, to save space. The first file to check is READ.ME, which may contain updated information about Serial++. You may also wish to examine the contents of PACKING.LST, which lists every file in the package, along with a brief description. The files included in the Serial++ package fall into the following groups: > Library files, SPPx.LIB. There is one library file for each memory model supported by Serial++. > Include files, *.H. These are C++ source includes that define the public interface of the classes that make up Serial++. > Demo related files, *.CPP, *.BAT, *.MAK, etc. These files are included to provide you with some examples of how to use Serial++. They include an executable demo program, SPPDEMO.EXE, which is ready to run. > Documentation, READ.ME, PACKING.LST, and the file that contains this document, SPPMAN.TXT. In order to begin using Serial++, you must place the library and include files in a directory where the C++ compiler and linker 6 can locate them. You have several options as to where to keep these files, as explained below. The placement of the documentation and demo files is of course not critical, they may be placed in any convenient directory, or removed after installation. Installing .LIB Library Files The goal with the .LIB files is to get them into the library search path used by the Borland C++ linker, TLINK. There are three ways to accomplish this: 1 Keep the libraries in the directory where you normally compile and link programs. The Borland C++ compiler will automatically search the current directory for any .LIB file explicitly listed in a project or on the command line of the command line compiler. This is the simplest of the three options. If the directory you expanded SPP.EXE in happens to be the directory where you compile and link, your libraries are installed! - OR - 2 Copy the Serial++ libraries into the directory where the standard libraries provided by Borland reside. This directory is also automatically searched by the compiler. In most installations, this would be directory: \BORLANDC\LIB unless you have changed the default Borland directory names. From the directory where you expanded SPP.EXE, issue these DOS commands: C:> COPY SPP?.LIB \BORLANDC\LIB (or whatever it is on your system) C:> DEL SPP?.LIB (to get rid of the temporary copies.) - OR - 3 Keep the libraries in their own directory, and change the compiler's library search path. This can be accomplished in several ways: If you use the Borland IDE compiler, from within the environment select Options Directories, and add to the beginning of the search path the directory that will contain the Serial++ libraries. If you wished to place them in directory \SPP for example, the new library search 7 path might look like: \SPP;\BORLAND\LIB;... Be sure to save the environment after making the change by selecting Options Save from the menu. Alternatively, you could use the BCINST program provided with Borland C++ to make the change above in the IDE program itself, BC.EXE. Again, add the path to the Serial++ library directory and a semicolon to the beginning of the library search path. If you prefer the command line compiler BCC.EXE, with or without configuration files, you can achieve the same result as described above by using the compiler's -L switch. As above, changing the switch to read: -L\SPP;\BORLANDC\LIB;... would insert the path to our hypothetical Serial++ libraries directory into the search path. Installing .H Include Files Although the Borland C++ compiler handles searching for include files a little differently than libraries, a basically similar strategy will work for installing the SERIAL.H and BREAK.H include files. 1 Keep the include files in the directory where you normally compile and link programs. This is the default situation that the C++ compiler expects --as mentioned before, if the directory you expanded SPP.EXE in happens to be the directory where you compile and link, you're done! - OR - 2 Copy the Serial++ include files into the directory where the standard include files reside. This directory is also automatically searched by the compiler. In most installations, this would be directory: \BORLANDC\INCLUDE unless you have changed the default Borland directory names. From the directory where you expanded SPP.EXE, issue these DOS commands: C:> COPY SERIAL.H \BORLANDC\INCLUDE C:> COPY BREAK.H \BORLANDC\INCLUDE (or whatever it is on your system) 8 C:> DEL BREAK.H C:> DEL SERIAL.H (to get rid of the temporary copies.) - OR - 3 Keep the include files in their own directory, and change the compiler's include search path. This can be accomplished in several ways: If you use the Borland IDE compiler, from within the environment select Options Directories, and add to the beginning of the include search path the directory that will contain the Serial++ include files. If you wished to place them in directory \SPP for example, the new include search path might look like: \SPP;\BORLAND\INCLUDE;... Be sure to save the environment after making the change by selecting Options Save from the menu. Alternatively, you could use the BCINST program provided with Borland C++ to make the change above in the IDE program itself, BC.EXE. Again, add the path to the Serial++ include files directory and a semicolon to the beginning of the include search path. If you prefer the command line compiler BCC.EXE, with or without configuration files, you can achieve the same result as described above by using the compiler's -I switch. As above, changing the switch to read: -I\SPP;\BORLANDC\INCLUDE;... would insert the path to our hypothetical Serial++ include files directory into the search path. Getting Started The first thing you will want to try is to execute the demo program supplied with Serial++: SPPDEMO.EXE. This is a very simple program that demonstrates some of the basic capabilities of the Serial++ classes. It allows you to open a conversation on either serial port, and accepts strings from the keyboard to send to the port, and waits up to two seconds for a reply from the port which it echoes to the screen. This program is useful because it provides a quick check that Serial++ will work with your hardware. It also gives you a 9 simple working example of source code that you can compile and link to check out your installation of Serial++. If your computer is equipped with a smart modem, you will find it a handy partner for trying out SPPDEMO.EXE. Try using SPPDEMO to send commands to the modem -- you should see SPPDEMO echo the modem's acknowledgements on the screen. If you have difficulty compiling and linking SPPDEMO using the supplied make file, check the configuration section at the bottom of the make file, and the TLINK command, for the library and include search paths. Make sure that the paths listed in the -I and -L compiler switches match the installation of the compiler on your machine. SPPDEMO.CPP shows a simple example of how to use the SerialPort class for reading and writing; for many of your applications this level of complexity will most likely be all you need. Be sure to browse through the function reference to get a complete picture of the flexibility of the Serial++ library. Using This Manual and Serial++ Perhaps the best way to become acquainted with Serial++ is to take the sample program, SPPDEMO.CPP, and modify it to suit you needs. However,by reviewing some background on the internal workings of the SerialPort and BreakTrap classes, along with function reference that follows, you will be able to write some very sophisticated serial port handling right from C++. The following sections contain a brief description of how SerialPort and BreakTrap are structured, and provide some practical information you will need to know to get the most out of the package. Serial Ports The first two serial ports in your system, COM1: and COM2:, are supported for input and output by the class SerialPort. You will need at least one instance of SerialPort for each port you wish to use in your program. You may have more than one instance of SerialPort associated with each physical port, but only one, the first instance to be created, will control the port parameters. Also, the port will remain under the control of your program until that first SerialPort instance, the one which opened the port, passes out of scope and has its destructor executed. We will come back to this point again later, as it has a major effect on how you will want to instantiate SerialPort objects in your programs. The SerialPort class consists of two portions: one portion is static, hidden from your application code and always resident. This portion, which is referred to as the port anchor (you will 10 notice a reference to a structure named PortAnchor in the definition of class SerialPort), contains the interrupt service routine code, along with a block of data required to service the port. This data includes such things as the pointer to the buffer used for port input, and it's current position. There is one port anchor for each of the two physical ports supported, and each is either busy or available for use by an instantiation of SerialPort for the duration of your program. The dynamic part of class SerialPort is the portion that gets created with each instantiation: it records the port parameters you set when you created it, and points to the port anchor corresponding to the port you specified in the constructor call. Each instance of SerialPort also knows if it is the owner of the port anchor: if it is the first instance to refer to that port, the parameters you specified (or defaulted to) at creation time are applied to the port and that instance owns the port until it is destroyed. Only the owner instance can set the speed, parity data and stop bit setting for a port, and the port is closed only when its owner is destroyed. You may create and destroy as many other instances of SerialPort for a given physical port as you need, only the owner will set the port up, or close it down. Although the set up parameters of the second and subsequent instances of SerialPort for a given physical port are ignored, all of the instances can read and write to the port. They will all do so at using the parameters established when the port owner instance was created. For example, in this code fragment: SerialPort com1(COM_1,B_2400,D_8,P_N,S_1); . . . SerialPort *newcom = new SerialPort(COM_1,B_1200); . . . com1.outstr("Hello,world"); newcom->outstr("\n...via modem!\n"); both instances pointing to COM1:, com1 and newcom, will output strings to the port at 2400 baud, the value set at the creation of the owner instance, com1. Note also in this example that when com1 goes out of scope and is destroyed, the port is closed. If instance newcom still exists after that happens, all attempts to communicate to the port with newcom will return error status, and interrogating the status of the port through newcom will show the line unavailable. This internal architecture of SerialPort allows you to initialize your ports early in your program, perhaps by declaring a SerialPort instance of file scope in your main module, and then to create a temporary instance anywhere you 11 need throughout your program to access the port, without the need to pass around or declare a global pointer to the port. All SerialPort instances, owners or not, can find and use the open port to which they refer. Another characteristic of SerialPort that is worth noting: the input and output member functions of SerialPort are all declared virtual. This facilitates creating derived classes from SerialPort, if you wish to perform some preprocessing of input streams, or post-processing of output streams. If you do override an inherited i/o member function, be sure to call the corresponding SerialPort routine from your new routine to perform the actual port i/o. Line and port status functions are not virtual in SerialPort. One final note: if you look at the definition of SerialPort in SERIAL.H, you will notice that the parameters passed to the constructor and returned by the get...() member functions are all defined as enum values, instead of simple integers. This was done for two reasons: first, since most of these parameters accept discrete rather than continuous values, using enums is an easy way to get the compiler to insure that no out of range values will be passed as parameters. The second reason is that by defining enums with user- meaningful names, the actual values passed can be whatever is convenient from a coding point of view. If you look at the enums at the beginning of SERIAL.H, you will notice that although the value names make sense, the values themselves really don't, outside of the context of the code that uses them. Break Trapping SerialPort uses keyboard break trapping to insure a safe and complete shutdown in the event of a user generated keyboard break. By default, SerialPort will restore all interrupt vectors to their original addresses and immediately exit to DOS when it detects a keyboard break. It will not return control to your program before exiting after a break. Checking for a trapped keyboard break is the first action performed in all of the i/o member functions, and most of the status functions of Serial++; but be aware that your program could run for quite some time until the next serial port operation discovers that a keyboard break has occurred. This behavior can be overridden by setting the SerialPort constructor parameter brk_off non-zero (true). This flag causes SerialPort to ignore trapped breaks, and continue to execute without interruption. If you use SerialPort with breaks ignored, you may wish to trap and handle keyboard breaks in your own application. This is 12 easily done by including an instance of the BreakTrap class in your program. BreakTrap is a very simple class that performs two services for your program. First, it traps keyboard breaks (Control-Break and Control-C), preventing them from interrupting your program, and second it provides a mechanism for your program to determine if a keyboard break has occurred. You may freely include and use BreakTrap in your programs that use SerialPort, because BreakTrap, like SerialPort, makes use of a static anchor structure that all instances share. Therefore no contention occurs regardless of the number of concurrent instances of BreakTrap or SerialPort. BreakTrap provides you application with a number of member functions with which it can determine if one or many keyboard breaks have occurred, reset the break flag, an even check to make sure that some other instance of BreakTrap hasn't released the trap. Please see the individual member function descriptions listed in the function reference for more information. Memory Models The Serial++ library is provided as four separate library files, that may be used with five different memory models supported by Borland C++. The files and models are: Memory Model Library File Tiny,Small SPPS.LIB Medium SPPM.LIB Compact SPPC.LIB Large SPPL.LIB Select the library file that matches the memory model you are using, and name that file as part of your project, or in the TLINK command in your make file. Consult your compiler documentation for further information on memory model support. Serial++ with Overlays The routines contained in SerialPort and BreakTrap contain static portions that once enabled must remain at their absolute 13 memory addresses. This fact is common to all interrupt service routines. Serial++ may be used in overlaid programs, as long as the Serial++ routines are loaded as part of the "root" or non- swapped portion of the program. As long as you can control the use of overlays and guarantee that the Serial++ routines will never get swapped out or written over, everything should work just fine. SerialPort Function Reference ++++++++++++++++++++++++++++++++++++++++ constructor Usage: SerialPort(CommPorts cp , Baud sp = B_1200, DataBits db = D_8, Parity ps = P_N, StopBits sb = S_1, size_t b_size = SERIALPORT_STD_BUF_SIZE, int brk_off = 0) Returns: n/a Description: The SerialPort constructor allocates an instance of SerialPort, and links it to the port anchor that services the requested port. If the port is not currently open, SerialPort opens it and makes this instance the port owner. The values passed into (or defaulted to) the constructor are used to set up the port. For the complete range of port parameters supported, please see the enums located in file SERIAL.H. If the requested port is already open, this instance is linked to it, and the port parameters passed in are ignored. 14 Parameters: CommPorts cp: Selects the desired port, COM1: or COM2:. No default. Baud sp: Selects the port speed. Defaults to 1200 baud. DataBits db: Selects number of data bits per character. Default is 8. Parity ps: Selects desired character parity checking. Default is no parity checking. StopBits sb: Selects number of stop bits per character. Default is 1. size_t b_size: Sets size of buffer to use for input characters from the selected port. Default is 2048 bytes, defined in SERIAL.H. int brk_off: Flag to turn off automatic keyboard break handling in SerialPort. If flag is true (non-zero), SerialPort ignores keyboard breaks and continues to operate if they occur. If flag is false (zero, this is the default), SerialPort does an orderly shutdown of all ports and exits to DOS immediately. Although this flag is set in the SerialPort constructor, the flag is sets is global to all ports, therefore if you wish to disable break handling in SerialPort, every SerialPort constructor must be called with brk_off non-zero. Examples: SerialPort com1(COM_1,2400,D_7,P_E,S_1); SerialPort *cport = new SerialPort(COM_2); // using defaults ++++++++++++++++++++++++++++++++++++++++ destructor Usage: n/a 15 Returns: n/a Description: The SerialPort destructor deallocates the storage associated with this instance. If this instance is the owner of the port, the port is closed and all trapped interrupts are returned to their prior state. If the current instance is not the port owner, the port is not closed. If you wish to change the parameters in use for a particular port, or close the port permanently, you must destroy the SerialPort instance that owns the port. After destroying the port owner, you may reopen the port with different parameters if you wish by instantiating a new SerialPort object linked to the port. A port may be closed or closed and re-opened even if other non-owner instances are linked to the port. Attempts to use the port while it is closed results in error returns from the SerialPort member functions, and causes no harm. Changed port parameters are not a problem either, because all instances linked to a particular port use the parameters set by the owner instance. Parameters: n/a Examples: SerialPort cport= new SerialPort(COM_1); // owns COM_1 ... if (... { SerialPort com1(COM_1,2400); // uses cport's parameters ... } // com1 destroyed, port still open ... delete cport; // now the port is closed ++++++++++++++++++++++++++++++++++++++++ getBreakOff Usage: int getBreakOff(void); 16 Returns: An integer value, true (non-zero) if SerialPort is ignoring keyboard breaks, false (zero) if keyboard breaks will interrupt SerialPort. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... int breaks_off = com1.getBreakOff(); ++++++++++++++++++++++++++++++++++++++++ getCommPort Usage: CommPorts getCommPort(void); Returns: The enum CommPorts value corresponding to the port to which this instance is linked. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... CommPorts cp = com1.getBreakOff(); 17 ++++++++++++++++++++++++++++++++++++++++ getDataBits Usage: DataBits getDataBits(void); Returns: The enum DataBits value in use by the port to which this instance is linked. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... DataBits db = com1.getDataBits(); ++++++++++++++++++++++++++++++++++++++++ getLSR Usage: int getLSR(LSR_Masks mm); Returns: An int value that is true (non-zero) if the 8250's Line Status Register bit corresponding to the mask passed in is 1, otherwise false (zero). Description: The 8250's Line Status Register reflects the current state of port data line. By selecting the mask corresponding to the line condition you wish to test from the enum LSR_Masks in SERIAL.H, you can use this routine to return the truth value of that line condition. You may OR together several masks if you wish to test for multiple conditions in a single call. 18 Parameters: LSR_Masks mm: One or more mask values selected from the enum defined in SERIAL.H: enum LSR_Masks { DR = 0x0001, // data ready OE = 0x0002, // overrun error PE = 0x0004, // parity error FE = 0x0008, // framing error BI = 0x0010, // break indication THRE = 0x0020, // THR empty TSRE = 0x0040 // Transmit Shift empty }; Examples: SerialPort com1(COM_1,B_2400); ... if (com1.getLSR(BI) // do this if line break detected { ... ++++++++++++++++++++++++++++++++++++++++ getMSR Usage: int getMSR(MSR_Masks mm); Returns: An int value that is true (non-zero) if the 8250's Modem Status Register bit corresponding to the mask passed in is 1, otherwise false (zero). Description: The 8250's Modem Status Register reflects the current state of several modem control lines. By selecting the mask corresponding to the status line you wish to test from the enum MSR_Masks in SERIAL.H, you can use this routine to return the truth value of the modem line. You may OR together several masks if you wish to test for multiple conditions in a single call. 19 Parameters: MSR_Masks mm: One or more mask values selected from the enum defined in SERIAL.H: enum MSR_Masks { DCTS = 0x0001, // delta clear to send DDSR = 0x0002, // delta data set ready TERI = 0x0004, // trailing edge ring ind DDCD = 0x0008, // delta data carrier detect CTS = 0x0010, // clear to send DSR = 0x0020, // data set ready RI = 0x0040, // ring indicator DCD = 0x0080 // data carrier detect }; Examples: SerialPort com1(COM_1,B_2400); ... if (com1.getMSR(DCD) // do this if carrier detected { ... ++++++++++++++++++++++++++++++++++++++++ getParity Usage: Parity getParity(void); Returns: The enum Parity value in use by the port to which this instance is linked. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... Parity ps = com1.getParity(); 20 ++++++++++++++++++++++++++++++++++++++++ getSpeed Usage: Baud getSpeed(void); Returns: The enum Baud value in use by the port to which this instance is linked. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... Baud sp = com1.getSpeed(); ++++++++++++++++++++++++++++++++++++++++ getStopBits Usage: StopBits getStopBits(void); Returns: The enum StopBits value in use by the port to which this instance is linked. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... StopBits sb = com1.getStopBits(); 21 ++++++++++++++++++++++++++++++++++++++++ inbyte Usage: int inbyte(unsigned char &cc,unsigned int timeout = 0); Returns: An int value, true (non-zero) if a character is read, otherwise false (zero). Description: This function reads one byte from the port's input buffer if it contains any. If the buffer is empty, it will wait the number of milliseconds indicated by the timeout parameter; if a byte appears in the buffer within that time period, it reads it and returns. If no byte appears in the buffer within the timeout period, the routine returns false, and the contents of the unsigned character reference is unchanged. Parameters: unsigned char cc: A reference to the byte to receive the character read from the port. unsigned int timeout: If positive, the number of milliseconds to wait for a character to appear if none are available immediately. If zero, no waiting occurs; if a character is not immediately available, none is returned. The default for this parameter is zero. Examples: SerialPort com1(COM_1); unsigned char cbuf[20]; ... if (com1.inbyte(cbuf[0],2000)) // char read within 2 secs. { ... // do this ++++++++++++++++++++++++++++++++++++++++ inmem Usage: int inmem(void *mp, size_t msize, unsigned int timeout=0); 22 Returns: An int value, true (non-zero) if all requested characters are read, otherwise false (zero). Description: This function reads a specified number of bytes from the port's input buffer. If the buffer is empty, it will wait the number of milliseconds indicated by the timeout parameter; if another byte appears in the buffer within that time period, it is read and the timer is reset. If no byte appears in the buffer within the timeout period, the routine returns false, however many bytes have already been read. Remember that the timeout period you specify is per character read, and not a total cumulative value for the entire count of characters requested. Parameters: void *mp: A void pointer to the starting byte to receive the characters read from the port. size_t msize: The count of characters to read, expressed as an unsigned short. (size_t is defined in STDLIB.H). unsigned int timeout: If positive, the number of milliseconds to wait for a character to appear if none are available immediately. If zero, no waiting occurs; if a character is not immediately available, none is returned. The default for this parameter is zero. Examples: SerialPort com1(COM_1); unsigned char cbuf[20]; ... if (com1.inmem(cbuf,sizeof(cbuf),2000)) { // all chars read within 2 secs. ... // do this 23 ++++++++++++++++++++++++++++++++++++++++ instr Usage: char *instr(char *buf, size_t maxlen, unsigned int timeout=0); Returns: The character pointer passed in as the first parameter. No error conditions are returned if a timeout or buffer overflow occurs, but the contents of the buffer are guaranteed to be null terminated. The buffer contents are unchanged if no characters are read. Description: This function reads bytes from the port's input buffer until and end-of-line is detected. If the buffer is empty, it will wait the number of milliseconds indicated by the timeout parameter; if another byte appears in the buffer within that time period, it is read and the timer is reset. If no byte appears in the buffer within the timeout period, the routine returns false, however many bytes have already been read. Remember that the timeout period you specify is per character read, and not a total cumulative value for the entire count of characters requested. Function instr looks for a carriage return (0x0a) or a carriage return and line feed (0x0a0d) as an end-of-line indication. These characters are not placed the output string. It does not check the data placed in the string for nulls (0x00); if one appears in the port it will be placed in the output string and have the effect of terminating it prematurely. If the buffer size is exceeded by the characters coming from the port, maxlen-1 data characters, plus a terminating null are returned. Parameters: char *buf: A pointer to the character buffer to receive the string read from the port. size_t msize: The maximum number of characters the buffer will accommodate, including the terminating null, expressed as an 24 unsigned short. (size_t is defined in STDLIB.H). unsigned int timeout: If positive, the number of milliseconds to wait for a character to appear if none are available immediately. If zero, no waiting occurs; if a character is not immediately available, none is returned. The default for this parameter is zero. Examples: SerialPort com1(COM_1); unsigned char cbuf[20]; ... *cbuf='\0'; com1.instr(cbuf,sizeof(cbuf),2000); if (*cbuf!='\0') { // any chars read within 2 secs. ... // do this ++++++++++++++++++++++++++++++++++++++++ isOwner Usage: int isOwner(void); Returns: An integer value that is true (non-zero) if this instance is the owner of the associated port, false (zero) if this instance is only linked to the port. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... if (com1.isOwner()) // if com1 is owner... { // do this ... 25 ++++++++++++++++++++++++++++++++++++++++ lineOK Usage: int lineOK(void); Returns: An integer value that is true (non-zero) if the port is open and available, and false (zero) otherwise. If keyboard breaks have not been disabled, lineOK() will report false if a keyboard break has been trapped. Description: n/a Parameters: n/a Examples: SerialPort com1(COM_1); ... if (com1.lineOK()) // if com1 is open and available... { ... // do this ++++++++++++++++++++++++++++++++++++++++ outbyte Usage: void outbyte(unsigned char cc); Returns: n/a Description: The unsigned character passed in to outbyte is written to the associated serial port. 26 Parameters: unsigned character cc: This character is written to the associated serial port. Examples: SerialPort com1(COM_1); ... com1.outbyte('A') // write character 'A' to COM_1 ... ++++++++++++++++++++++++++++++++++++++++ outmem Usage: void outmem(const void *mp, size_t msize); Returns: n/a Description: Writes a specified number of bytes from a specific memory location to the associated port. Parameters: const void *mp: Pointer to the first byte to write to the port. size_t msize: Number of bytes to write, expressed as an unsigned short (size_t is defined in STDLIB.H). Examples: SerialPort com1(COM_1); char cbuf[20]; ... com1.outmem(cbuf,sizeof(cbuf)) // write array to COM_1 ... 27 ++++++++++++++++++++++++++++++++++++++++ outstr Usage: void outstr(const char *buf); Returns: n/a Description: Writes the null terminated string pointed to by the input parameter to the associated port. outstr does not send the terminating null to the port, and does not send any extra characters (such as \n), after the string. The count of characters sent is equal to strlen(buf). Parameters: const char *buf: Pointer to the string to send to the associated port. Examples: SerialPort com1(COM_1); char cbuf[20]="ATZ"; ... com1.outstr(cbuf) // write string "ATZ" to COM_1 com1.outbyte('\n'); // send new line after ... ++++++++++++++++++++++++++++++++++++++++ sendBreak Usage: void sendBreak(int dur=750); Returns: n/a Description: This routine causes the associated serial port to send a line break for the number of milleseconds passed as the integer parameter. 28 Parameters: int dur: The duration of the line break, in milleseconds. Defaults to 750 milleseconds if omitted. Examples: SerialPort com1(COM_1); ... com1.sendBreak() // send 750 millisecond break on COM_1 ... ++++++++++++++++++++++++++++++++++++++++ setMCR Usage: int setMCR(MCR_Masks mm, int state); Returns: An integer value equal to that passed in as the int input parameter, state. Description: The 8250's Modem Control Register controls several features of the UART. By selecting the mask corresponding to the UART feature you wish to enable or disable from the enum MCR_Masks in SERIAL.H, you can use this routine to change the operating condition of the UART. You may OR together several masks if you wish to toggle multiple features in a single call. Parameters: MCR_Masks mm: One or more mask values selected from the enum defined in SERIAL.H: enum MCR_Masks { DTR = 0x0001, // data terminal ready RTS = 0x0002, // request to send OUT1 = 0x0004, // aux user o/p 1 OUT2 = 0x0008, // aux user o/p 2 LOOP = 0x0010 // enable loopback }; Be very careful about changing the state of OUT1, OUT2, and LOOP. Do not toggle these lines unless you know exactly what 29 you are doing -- you could disable the serial port altogether. int state: This integer parameter turns on the features requested if it is true (non- zero), and turns off the feature is it is false (zero). Examples: SerialPort com1(COM_1,B_2400); int set_state = 1; com1.setMCR(DTR,set_state); // set DTR on ++++++++++++++++++++++++++++++++++++++++ unbyte Usage: void unbyte(unsigned char cc); Returns: n/a Description: The unsigned character passed in to unbyte is pushed back into the buffer of the associated serial port as the next character to be read. This routine is useful if you need to "look ahead" in the input stream for the second character of a two character escape sequence. Parameters: unsigned character cc: This character is returned to the input buffer of the associated serial port. Examples: SerialPort com1(COM_1); unsigned char cc ... com1.inbyte(cc) // read character from COM_1 if (cc=='\t') ... // do this if a tab else com1.unbyte(cc); // otherwise put it back for next read 30 BreakTrap Function Reference ++++++++++++++++++++++++++++++++++++++++ constructor Usage: BreakTrap(void); Returns: n/a Description: The BreakTrap constructor allocates an instance of BreakTrap, and links it to the break trap anchor that services keyboard break interrupts. If the trap is not currently set, BreakTrap sets it and makes this instance the trap owner. If the break trap is already set, this instance is linked to it, and full access to all trap flags and controls. In either case, after creating an instance of BreakTrap, the break trap anchor routines capture each Control-Break and Control-C pressed, and record theses events by incrementing a counter. No other response to the break is made, and any routine that contains an instance of BreakTrap within its scope can check the counter at any time to determine if a break has occurred. Parameters: n/a Examples: BreakTrap bt; ... BreakTrap *btp = new BreakTrap; ... ++++++++++++++++++++++++++++++++++++++++ destructor Usage: n/a 31 Returns: n/a Description: The BreakTrap destructor deallocates the storage associated with this instance. If this instance is the owner of the trap, the trap is released and all trapped interrupts are returned to their prior state. If the current instance is not the trap owner, the trap is not released. If you wish to release the trap, you must destroy the BreakTrap instance that owns the trap. A trap may be released or released and set again even if other non-owner instances remain linked to the trap. Attempts to use the trap while it is released returns indications that no breaks have occurred, and causes no harm. Parameters: n/a Examples: BreakTrap bt1= new BreakTrap; // bt1 owns trap if (... { BreakTrap bt2; // bt2 is just linked ... } // bt2 destroyed, trap still set ... delete bt1 // now the trap is released; ++++++++++++++++++++++++++++++++++++++++ breakCt Usage: unsigned int breakCt(void); Returns: An unsigned int value that is the count of the number of keyboard breaks that have occurred since the counter was last reset. 32 Description: Each time a Control-Break or Control-C is pressed while break trapping is enabled, a counter is incremented by BreakTrap. This routine returns the current count of break events. This counter can be reset by reset() member function described below. Parameters: n/a Examples: BreakTrap bt; ... if (bt.breakCt()>1) // if more than one break occurred { ... // do this ++++++++++++++++++++++++++++++++++++++++ isBreak Usage: int isBreak(void); Returns: An integer value that is true (non-zero) if at least one keyboard break has been counted since the last reset, otherwise false (zero). Description: Each time a Control-Break or Control-C is pressed while break trapping is enabled, a counter is incremented by BreakTrap. This routine returns true (non-zero) if the current count of break events is non-zero. Parameters: n/a 33 Examples: BreakTrap bt; ... if (bt.isBreak()) // if any breaks have occurred { ... // do this ++++++++++++++++++++++++++++++++++++++++ isCaptured Usage: int isCaptured(void); Returns: An integer value that is true (non-zero) if the break trap anchor is currently active and trapping breaks, otherwise false (zero). Description: When more that one instance of BreakTrap exist in a program, only one is the owner of the break trap. If the owner instance is destroyed, the trap is released -- however the non-owner instances continue to exist. This function allows any instance, owner or otherwise, to verify that the trap is currently set and keyboard breaks are being trapped. If the owner instance has been destroyed, and the trap is released, any other instance checking for breaks will see no breaks counted, i.e. will be unaware that the trap has been released. It is therefore good practice to use isCaptured() whenever multiple instances of BreakTrap are used. Parameters: n/a Examples: BreakTrap bt; ... if (bt.isCaptured()&&bt.isBreak()) // if trap is set and { // any breaks have occurred ... // do this 34 ++++++++++++++++++++++++++++++++++++++++ isOwner Usage: int isOwner(void); Returns: An integer value that is true (non-zero) if this instance is the owner of the break trap, otherwise false (zero). Description: This routine enables any instance to determine if it is the owner of the break trap. Since the destruction of the trap owner shuts off break trapping, and leaves the application program susceptible to user interruption, it is dangerous to destroy the trap owner. By checking to determine if a particular instance is trap owner before deleting it, you can avoid losing break protection. Parameters: n/a Examples: ... BreakTrap *bt = new BreakTrap; ... if (!bt->isOwner()) // if instance is not owner delete bt: // okay to delete it ... ++++++++++++++++++++++++++++++++++++++++ operator() Usage: int operator()(void); Returns: An integer value that is true (non-zero) if breaks are currently being trapped and at least one break has been counted since the last reset, otherwise false (zero). 35 Description: This overloaded function operator provides a convenient shorthand way to query the break trap about its state. The trap is tested to determine whether it is active and whether any breaks have been occurred. After testing the trap, this function also resets it, i.e. sets the count of breaks trapped since the last reset to zero. Invoking this overloaded operator is the equivalent of making three consecutive member functions: isCaptured(), isBreak() and reset(). See the example below. Parameters: n/a Examples: BreakTrap bt; ... if (bt()) // test for trap open and breaks occurred { // break counter reset after test ... // breaks are detected, do this The above example is equivalent to the following code: BreakTrap bt; ... if (bt.isCaptured()) // test if trap operating if (bt.isBreak()) // any breaks caught? { bt.reset(); // reset break counter ... // do this Note also that this overloaded operator notation requires a reference to the instance, not a pointer to it. If you have a pointer to the instance, you must dereference in explicitly: BreakTrap *btp = new BreakTrap; ... if ((*btp)()) // test and reset { ... // do this if breaks have occurred. ++++++++++++++++++++++++++++++++++++++++ reset Usage: void reset(void); 36 Returns: n/a Description: Each time a Control-Break or Control-C is pressed while break trapping is enabled, a counter is incremented by BreakTrap. This routine resets that counter to zero. Parameters: n/a Examples: BreakTrap bt; ... if (bt.isBreak()) // any breaks caught? { bt.reset(); // reset break counter ... // do this Serial++ License and Registration Serial++ is Shareware Serial++ is a copyrighted computer program which is being distributed as shareware. It is not a public domain program, and it is not free. Shareware is a distribution technique allows you the user a legal but limited trial period to evaluate a program before purchase. If you continue to use the program after the trial period has ended, you must pay for the program by registering it. You are also allowed to distribute evaluation copies of this software to others subject to certain limitations detailed below. This system of "try before you buy" allows you the user to get the most out of your software dollar by evaluating a prospective software purchase under its actual conditions of use. For small software vendors such as Cortlandt Technologies, it represents a viable way of reaching a potential market, without the large costs and risks of self- 37 publishing. Many fine programs in commercial release today would not be available if the shareware concept did not exist. Please support the shareware concept by registering those programs you actually use and by passing them on to others. Registration Information Serial++ is provided at no charge for evaluation purposes only. This shareware version of Serial++ is the complete working version of the library, not a crippled or demo copy. Cortlandt Technologies, hereby grants you a limited license to use this software for evaluation purposes only for a period not to exceed 30 days. If you intend to continue using this software after the 30-day evaluation period, you must register it by paying the registration fee to Cortlandt Technologies. Serial++ is a library of routines which may be included in software you develop and distribute with no additional royalties ONLY IF YOU HAVE PAID THE ONE TIME REGISTRATION FEE TO CORTLANDT TECHNOLOGIES. If you have registered your copy of Serial++, you have the right to unrestricted distribution of any software you develop using it. Using this software after the evaluation period has ended, or distributing your own software developed with it, without registering it is a violation of the terms of this limited license. The $24.95 registration fee licenses one copy of the software for use on one computer at any given time. You may have copies of Serial++ on more than one computer, as long as it is not possible for more than one copy to be in use at one time. Site licenses, or multiple computers on a local area network, are quoted on a per case basis, please contact Cortlandt Technologies for current multiple user license information. Upon registering your copy of Serial++, you will receive: > A printed manual > Complete BORLAND C++ source code for the Serial++ class library. > The most current version of the Serial++ library. This includes all maintenance changes and revisions made at the time you place your order. > Free technical support, via mail or Compuserve for one year after registration date. > Notification of future releases of Serial++. 38 Limited Distribution License Cortlandt Technologies encourages you to freely copy and distribute the unregistered version of Serial++ subject to the following restrictions: > You may only distribute the complete Serial++ package, in its original self-extracting archive file. You may not distribute the unarchived form of any Serial++ files. > None of the files comprising Serial++, program or documentation, may be modified in any way and must be distributed as a complete package, intact. > You may charge a distribution fee for the package, but you must not represent in any way that you are selling the software itself. > Documentation in printed form may not be reproduced in whole or in part, using any means, without the prior written permission of Cortlandt Technologies. This restriction includes both bound documentation, and printouts you make of the documentation included in the distribution file on diskette. > You may not use, copy, rent, lease, sell or transfer the licensed program except as provided in this agreement. Any such unauthorized use shall result in immediate and automatic termination of this license. > Cortlandt Technologies reserves the right to withdraw permission from any vendor to distribute our products at any time and for any reason. All rights not expressly granted here are reserved by Cortlandt Technologies, 39 Serial++ Order Form To register your copy of Serial++ please send $24.95 and this form to: Cortlandt Technologies P.O. Box 195 Pleasantville, NY 10570 You will receive the latest version of Serial++ complete with source code, a printed version of the manual, be eligible for technical support via mail and Compuserv, and be placed in our user database to automatically receive notices of upgrades and releases. See the section in this manual on licensing and registration for more details. Please fill in the information requested below: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Name _________________________________________________________ Title _________________________________________________________ Company _________________________________________________________ Address _________________________________________________________ _________________________________________________________ City _________________________________________________________ State _______ Postal _______ Country _________________________ (Prov) Code Daytime Phone ______________________ Evenings __________________ __ I have enclosed $24.95 in __ Check __ Money Order. __ I am interested in multiple user or site license. Also, please tell us how you heard about Serial++, and where you got your evaluation copy? _________________________________________________________________ Thank you for registering your copy of Serial++! 40 Index 8250 UART 5 Archive file 6 Aux user o/p 1 29 Aux user o/p 2 29 Baud 21 BI 19 Break trapping 12 BreakCt 33 BreakTrap 13 Clear to send 20 CommPorts 14, 17 Constructor, BreakTrap 31 Constructor, SerialPort 14, 15 CTS 20 Data bits 15 Data carrier detect 20 Data ready 19 Data set ready 20 Data terminal ready 29 DataBits 18 DCD 20 DCTS 20 DDCD 20 DDSR 20 Delta clear to send 20 Delta data carrier detect 20 Delta data set ready 20 Destructor, BreakTrap 32 Destructor, SerialPort 15, 16 Distribution of Serial++ 39 DR 19 DSR 20 DTR 29 Enum parameters 12 FE 19 Framing error 19 GetBreakOff 17 GetCommPort 18 GetDataBits 18 GetLSR 19 GetMSR 20 GetParity 21 GetSpeed 21 GetStopBits 21 Inbyte 22 Include files 6, 7 Inmem 24 Input buffer 15 Installation 6 Instantiation 11 Instr 25 Interrupt service routine 11 Interrupt service routines, in overlays 14 Interrupts 5, 16 IsBreak 34 IsCaptured 35 IsOwner, BreakTrap 35 IsOwner, SerialPort 26 Keyboard breaks 15, 17, 26 Library files 6, 7, 13 Line break 28 Line break indication 19 Line Status Register 18 LineOK 26 LOOP 29 Loopback enable 29 LSR 18 LSR_Masks 18 MCR 29 MCR_Masks 29 Memory models 13 Modem Control Register 29 Modem Status Register 19 MS-DOS 5 MSR 19 MSR_Masks 19 Non-owner instances 16 OE 19 Order form, Serial++ 40 OUT1 29 OUT2 29 Outbyte 27 Outmem 28 Outstr 28 Overlays 14 Overloaded operator(), BreakTrap 36 Overrun error 19 Owner 11, 25, 34 PACKING.LST 6 Parity 15, 20 Parity error 19 PE 19 Port addresses 5 Port anchor 10 Port parameters 11, 16 Port speed 15 PortAnchor 11 READ.ME 6 Registration of Serial++ 39 Request to send 29 Reset, BreakTrap 37 RI 20 Ring indicator 20 RTS 29 SendBreak 29 SerialPort 12 SetMCR 30 Shareware 38 Smart modem 10 SPP.EXE 6 SPPDEMO.EXE 9 SPPMAN.TXT 6 SPPx.LIB 6 Static 13 Stop bits 15 StopBits 21 TERI 20 THR empty 19 THRE 19 Timeout 22, 23, 24, 25 Trailing edge ring indicator 20 Transmit Shift empty 19 TSR's 4, 5 TSRE 19 Unbyte 30 Virtual functions 12